﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media.Imaging;

namespace ComputationVisualizer
{
    public class PlayerModel
    {
        private double _framesCount, _currentFrameNumber, _speed;
        private Timer _timer;

        #region Public Properties

        public double MinTimeValue { get; private set; }

        public double MaxTimeValue { get; private set; }

        public double Speed
        {
            get { return _speed; }
            set
            {
                _speed = Math.Round(value, 3);
                RaiseEvent(_speedNumberUpdated);
            }
        }

        public double CurrentTimeValue
        {
            get { return _currentFrameNumber; }
            set
            {
                if (value >= MinTimeValue && value < MaxTimeValue)
                {
                    _currentFrameNumber = value;
                    RaiseEvent(_frameNumberUpdated);
                }
            }
        }

        public double FramesCount
        {
            get { return _framesCount; }
            set
            {
                _framesCount = value;
                MaxTimeValue = _framesCount - 1;
                if (CurrentTimeValue > MaxTimeValue)
                    CurrentTimeValue = MinTimeValue;
                RaiseEvent(_maxTimeUpdated);
            }
        }

        public Func<double, BitmapSource> BitmapProvider { get; set; }

        public BitmapSource CurrentBitmapSource { get { return BitmapProvider(CurrentTimeValue); } }

        #endregion

        #region Events
        private event EventHandler _frameNumberUpdated;
        private event EventHandler _speedNumberUpdated;
        private event EventHandler _startedPlaying;
        private event EventHandler _stoppedPlaying;
        private event EventHandler _maxTimeUpdated;

        public event EventHandler FrameNumberUpdated
        {
            add { _frameNumberUpdated += value; }
            remove { _frameNumberUpdated -= value; }
        }

        public event EventHandler SpeedNumberUpdated
        {
            add { _speedNumberUpdated += value; }
            remove { _speedNumberUpdated -= value; }
        }

        public event EventHandler StartedPlaying
        {
            add { _startedPlaying += value; }
            remove { _startedPlaying -= value; }
        }

        public event EventHandler StoppedPlaying
        {
            add { _stoppedPlaying += value; }
            remove { _stoppedPlaying -= value; }
        }

        public event EventHandler MaxTimeUpdated
        {
            add { _maxTimeUpdated += value; }
            remove { _maxTimeUpdated -= value; }
        }
        #endregion

        public PlayerModel()
        {
            MinTimeValue = 0;
            Speed = 1;
            CurrentTimeValue = MinTimeValue;  
        }

        public void StopPlaying()
        {
            if (_timer != null)
                _timer.Stop();
            RaiseEvent(_stoppedPlaying);
        }

        public void StartPlaying()
        {
            _timer = new Timer { Interval = (int)(1000.0 / _speed) };
            _timer.Tick += timerTick;
            _timer.Start();
            RaiseEvent(_startedPlaying);
        }

        #region Private Methods

        private void RaiseEvent(EventHandler raisedEvent)
        {
            if (raisedEvent != null)
                raisedEvent(this, null);
        }

        private void timerTick(object sender, EventArgs e)
        {
            var oldTime = CurrentTimeValue;
            CurrentTimeValue += 1;
            if (CurrentTimeValue - oldTime <= 0.0001)
                CurrentTimeValue = MaxTimeValue;
        }

        #endregion
    }
}
